package br.com.lm.anotacoes;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author Robson Motta
 * Pesquisa por objetos ".class" em varias origens do projeto
 */
public class ReadClassesUtil {

    /**
     * @return - Retorna todos os nomes de classes contida em META-INF/persistence.xml
    */
    public static List<String> getClassesFromPersistenceXml() {
        List<String> classesFromPersistence = null;
	try {
            Class<?> cl = new Object(){}.getClass().getEnclosingClass(); //Obter objeto "getClass()" dentro de um static method		
            Enumeration<URL> resources = cl.getClassLoader().getResources("META-INF/persistence.xml");
            //Enumeration<URL> resources = getClass().getClassLoader().getResources("META-INF/persistence.xml"); 			
            while (resources.hasMoreElements()) {
                File fXmlFile = new File(resources.nextElement().toURI());
                DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                Document doc = dBuilder.parse(fXmlFile);
                doc.getDocumentElement().normalize();
                NodeList nList = doc.getElementsByTagName("class");
                for (int temp = 0; temp < nList.getLength(); temp++) {
                    Node nNode = nList.item(temp);
                    if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                        Element eElement = (Element) nNode;
                        if (classesFromPersistence == null) 
                            classesFromPersistence = new ArrayList<String>();
                            classesFromPersistence.add(eElement.getTextContent());
                    }
                }
		break;
            }	
	}
        catch (Exception e) {}
        return classesFromPersistence;
    }	
	
    /**
     * @param packageName - Identificacao do package/diretorio que deseja a extracao 
     * @return - Retorna todos os nomes de classe contido em um diretorio 
     */
    public static List<String>getClassNamesFromPackage(String packageName) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	URL packageURL;
	ArrayList<String> names = new ArrayList<String>();
	packageName = packageName.replace(".", "/");
	packageURL = classLoader.getResource(packageName);	    
	if(packageURL.getProtocol().equals("jar")){
            try {
                String jarFileName;
		JarFile jf ;
		Enumeration<JarEntry> jarEntries;
		String entryName;
		// build jar file name, then loop through zipped entries
		jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
		jarFileName = jarFileName.substring(5,jarFileName.indexOf("!"));
		jf = new JarFile(jarFileName);
		jarEntries = jf.entries();
		while(jarEntries.hasMoreElements()){
                    entryName = jarEntries.nextElement().getName();
		    if (entryName.endsWith(".class")) {
                        if(entryName.startsWith(packageName) && entryName.length()>packageName.length()+5){
                            entryName = entryName.substring(packageName.length(),entryName.lastIndexOf('.'));
			    names.add(packageName.concat(".").concat(entryName));
			}		            	
		    }
		 }	    		
	    }
	    catch (IOException e) {}  		
                // loop through files in classpath
        } else{
            try {	    		
	    	File folder = new File(packageURL.toURI());	    		
		File[] contenuti = folder.listFiles();
		String entryName;
		for(File actual: contenuti){
                    entryName = actual.getName();		
		    if (entryName.endsWith(".class")) {
                        entryName = entryName.substring(0, entryName.lastIndexOf('.'));
			names.add(packageName.concat(".").concat(entryName));		            	
		    }
		}	
            }catch (Exception e) {}
	}
	return names;
    }

    /**
     * @return - Retorna todos os nomes de classe contido em um Web-Inf/classes
     */
    public static List<String>getClassNamesFromWebInfClasses() {
        String contextWebInf = ReadContextWebInf.getContextWebInf(null);
        ArrayList<String> names = new ArrayList<String>();
        if (contextWebInf != null && !contextWebInf.trim().equals("")) {
            try {	    		
	    	File folder = new File(contextWebInf);	    		
		File[] contenuti = folder.listFiles();
		String entryName;
		for(File actual: contenuti) {
                    entryName = actual.getName();		
		    if (entryName.endsWith(".class")) {
                        entryName = entryName.substring(0, entryName.lastIndexOf('.'));
			names.add(actual.getPath().concat(".").concat(entryName));		            	
		    }
		}	
            }catch (Exception e) {}
        }
	return names;
    }
    
}